#include <QtCore>
#include <QTextEdit>
#include <QDateTime>
#include <QMessageBox>

#include "DataMonitor.h"

DataMonitor::DataMonitor(QObject * parent) : QObject(parent), reading(0), compass(0), possource(0), serviceProvider(0)
{
    qDebug() << "Kicsi kutya tarka";
    initialize();
    connect(&timer, SIGNAL(timeout()), this, SLOT(timerFired()));
    timer.start(1000);

    compass = new QCompass(this);
    if (compass)
    {
        //compass->setDataRate(500);
        if (compass->start())
        {
            reading = compass->reading();
            if (reading)
            {
                readingChanged();
                connect(compass, SIGNAL(readingChanged()), this, SLOT(readingChanged()));
            }
        }
        if (!compass->isActive())
        {
            qWarning("Compasssensor didn't start!");
            qDebug() << "Compass is not started!";
        }
    }

    possource = QGeoPositionInfoSource::createDefaultSource(this);
    if (possource) {
        possource->setPreferredPositioningMethods(QGeoPositionInfoSource::AllPositioningMethods);
        possource->setUpdateInterval(3000);
        connect(possource, SIGNAL(positionUpdated(QGeoPositionInfo)), this, SLOT(OnPositionUpdate(QGeoPositionInfo)));
        possource->startUpdates();
    }

    /*
    satsource = QGeoSatelliteInfoSource::createDefaultSource(this);
    if (satsource) {
        connect(satsource, SIGNAL(satellitesInViewUpdated(QList<QGeoSatelliteInfo>)),
                this, SLOT(UpdateSatsInView(QList<QGeoSatelliteInfo>)));
        connect(satsource, SIGNAL(satellitesInUseUpdated(QList<QGeoSatelliteInfo>)),
                this, SLOT(UpdateSatsInUse(QList<QGeoSatelliteInfo>)));
        possource->setUpdateInterval(500);
        satsource->startUpdates();
    }
     */
}

void DataMonitor::initialize()
{
    if (serviceProvider)
        delete serviceProvider;

    // check we have a valid default provider

    QList<QString> providers = QGeoServiceProvider::availableServiceProviders();
    if (providers.size() < 1) {
        qWarning("No service providers are available");
        QCoreApplication::quit();
        return;
    }

    foreach (QString provider, providers) {
        serviceProvider = new QGeoServiceProvider(provider);
        if (serviceProvider->mappingManager() &&
                serviceProvider->searchManager() &&
                serviceProvider->routingManager())
            break;
    }

    if (serviceProvider->error() != QGeoServiceProvider::NoError) {
        qWarning("Error loading geoservice plugin");
        QCoreApplication::quit();
        return;
    }

    if (!serviceProvider->mappingManager() ||
            !serviceProvider->searchManager() ||
            !serviceProvider->routingManager()) {
        qWarning("No geoservice found with mapping/search/routing");
        QCoreApplication::quit();
        return;
    }

    if (possource)
        delete possource;

    // set up position feeds (eg GPS)

    possource = QGeoPositionInfoSource::createDefaultSource(this);

    if (!possource) {
        qWarning("Could not open GPS");
    } else {
        possource->setUpdateInterval(3000);
        possource->setPreferredPositioningMethods(QGeoPositionInfoSource::AllPositioningMethods);
        connect(possource, SIGNAL(positionUpdated(QGeoPositionInfo)),
                this, SLOT(OnPositionUpdate(QGeoPositionInfo)));
        possource->startUpdates();
        qDebug() << "Waiting for GPS...";
    }

    connect(&timer, SIGNAL(timeout()), this, SLOT(timerFired()));
    timer.start(1000);
}

DataMonitor::~DataMonitor()
{
    if (timer.isActive()) {
        qDebug() << "Stopping timers...";
        timer.stop();
    }
    if (compass) {
        if(compass->isActive()) {
            compass->stop();
            qDebug() << "Shutting down compass...";
        }
    }
    if (possource) {
        qDebug() << "Shutting down position updates...";
        possource->stopUpdates();
        delete possource;
    }

    if (serviceProvider) {
        qDebug() << "Shutting down the service provider...";
        delete serviceProvider;
    }

}

// slots

void DataMonitor::timerFired()
{
    possource->requestUpdate();
    //satsource->requestUpdate();
    //qDebug() << QString("Time fired: %1").arg(QDateTime::currentDateTime().toString());
}

void DataMonitor::OnPositionUpdate(const QGeoPositionInfo& info)
{
    posinfo = info;
    /*
    if (posinfo.coordinate().latitude() != posinfo.coordinate().latitude() &&
            posinfo.coordinate().longitude() != posinfo.coordinate().longitude()) // check for NaN
     */
    emit positionChanged(latitude(), longitude());
    emit positionChanged();
    emit speedChanged();
    emit altitudeChanged();
    qDebug() << QString("Position updated: Date/time = %1, Coordinate = %2").arg(info.timestamp().toString()).arg(info.coordinate().toString());

    QGeoCoordinate qgc = posinfo.coordinate();
    if (qgc.isValid())
        emit positionChanged(qgc);
}

void DataMonitor::UpdateSatsInUse(const QList<QGeoSatelliteInfo>& inuse)
{
    satsinuse = inuse;
    emit satellitesChanged();
    foreach(QGeoSatelliteInfo info, inuse) {
        qDebug() << QString("Satellite in use: prn = %1, signal strength = %2").arg(info.prnNumber()).arg(info.signalStrength());
    }
}


void DataMonitor::UpdateSatsInView(const QList<QGeoSatelliteInfo>& inview)
{
    satsinview = inview;
    emit satellitesChanged();
    foreach(QGeoSatelliteInfo info, inview) {
        qDebug() << QString("Satellite in view: prn = %1, signal strength = %2").arg(info.prnNumber()).arg(info.signalStrength());
    }

}


void DataMonitor::readingChanged()
{ emit headingChanged(); /* qDebug() << QString("Azimuth changed: %1").arg(reading->azimuth()); */ }

// Compass
Q_INVOKABLE int DataMonitor::heading()
{ if (reading) { return reading->azimuth(); } else { return 0; } }

Q_INVOKABLE int DataMonitor::bearing()
{ return 0; }

// Position
Q_INVOKABLE double DataMonitor::latitude()
{
    double lat = posinfo.coordinate().latitude();
    if (lat != lat) // check for NaN
        return 0;
    else
        return lat;
}

Q_INVOKABLE double DataMonitor::longitude()
{
    double lon = posinfo.coordinate().longitude();
    if (lon != lon) // check for NaN
        return 0;
    else
        return lon;
}

Q_INVOKABLE double DataMonitor::altitude()
{
    double alt = posinfo.coordinate().altitude();
    if (alt != alt) // check for NaN
        return 0;
    else
        return alt;
}

// StatusBar
Q_INVOKABLE QString DataMonitor::position()
{
    QString s = QString::number(latitude(),'g',8) + "  " + QString::number(longitude(),'g',8);
    return s;
}

/*
// Clock
Q_INVOKABLE QDateTime DataMonitor::time()
{ return QDateTime::currentDateTime(); }

Q_INVOKABLE QDateTime DataMonitor::triptime()
{ return QDateTime::currentDateTime(); }

Q_INVOKABLE QDateTime DataMonitor::eta()
{ return QDateTime::currentDateTime(); }


// Speedometer
Q_INVOKABLE double DataMonitor::speed()
{
    if (posinfo.hasAttribute(QGeoPositionInfo::GroundSpeed))
        return posinfo.attribute(QGeoPositionInfo::GroundSpeed)*3.6;
    else
        return 0;
}

Q_INVOKABLE double DataMonitor::distance()
{
    return 1523.9;
}

// Levels
Q_INVOKABLE int DataMonitor::compassLevel()
{ return (reading->calibrationLevel()*100); }

Q_INVOKABLE int DataMonitor::horizontalLevel()
{
    int result = 0;
    if (posinfo.hasAttribute(QGeoPositionInfo::HorizontalAccuracy))
    {
        int r = posinfo.attribute(QGeoPositionInfo::HorizontalAccuracy);
        if (r < 300)
            result = 100 - r/3;
    }
    return result;
}

Q_INVOKABLE int DataMonitor::verticalLevel()
{
    int result = 0;
    if (posinfo.hasAttribute(QGeoPositionInfo::VerticalAccuracy))
    {
        int r = posinfo.attribute(QGeoPositionInfo::VerticalAccuracy);
        if (r < 300)
            result = 100 - r/3;
    }
    return result;
}

*/
